package gbench.sandbox.data;

import org.junit.jupiter.api.Test;

import static gbench.sandbox.data.index.Algorithm.KEY_VALUE;
import static gbench.sandbox.data.index.TableSearchEngine.KTB;
import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.matlib.algebra.lisp.MyRecord.REC;
import static gbench.common.tree.LittleTree.Term.FT;
import gbench.commonApp.data.DataApp;

import gbench.sandbox.data.index.TableSearchEngine;
import io.vavr.collection.Stream;
import gbench.sandbox.data.index.Algorithm;
import gbench.common.fs.FileSystem;
import gbench.common.matlib.algebra.lisp.DFrame;
import gbench.common.matlib.algebra.lisp.IRecord;
import gbench.common.tree.LittleTree;
import gbench.common.tree.LittleTree.CronTime;
import gbench.common.tree.LittleTree.Json;
import gbench.common.tree.LittleTree.SQL;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Random;
import java.util.UUID;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * 
 * @author Administrator
 *
 */
public class JunitTableSearchEngine {

    @Test
    public void foo() {
        final var file = FileSystem.path("数字医院.xlsx", getClass());
        final var algorithmIds = new Algorithm[] { KEY_VALUE }; // 合集种类
        final var srchEngne = TableSearchEngine.of("第一用户", file, algorithmIds,
                (alogrithmId, dataItem) -> "id,name".split(","), "费用,收入,科室,患者,医生".split(","));

        srchEngne.withTransaction(datasess -> {
            // 数据翻译
            final var rec_id = REC("fee", 1, "revenue", 10102, "dept", 5, "date", LocalDateTime.now());
            final var r = datasess.findOne(rec_id, "id", e -> e);
            println("parse", rec_id, r, r.pathget("fee/name", e -> e.toString()));

            // 数据收入
            final var rec_name = REC("patient", "张梦婷", "doctor", "蒋春桥", "fee", "西药费", "revenue", "接生收入", "dept", "胸外科",
                    "date", LocalDateTime.now());
            println(datasess.findOne(rec_name, "name", e -> e));
            println(datasess.encode(rec_name));
            println(datasess.decode(rec_id));
            return null;
        }, KEY_VALUE, "fee,费用,revenue,收入,dept,科室,patient,患者,doctor,医生".split(","));

    }

    @Test
    public void bar() {
        final var file = FileSystem.path("数字医院.xlsx", getClass());
        final var srchEngne = TableSearchEngine.of("第一用户", file, "费用,收入,科室,患者,医生".split(","));

        final var flds = "code,exec_unit,name,audit_code,charge_amount,effective_date,percentage_1_5,self_flag,separate_flag,suppress_flag,bill_item"
                .split(",");
        final var rb = IRecord.rb(Arrays.asList(flds));
        final var result = srchEngne.withTransaction(sess -> {
            final var tpl = "$0,$1,$2,$3,$4,$5,1,1,1,1,$6";
            final Object[] params = FT(tpl, UUID.randomUUID(), "普通外科", "血常规化验费用", "化验收入", 100, "2020-10-13 00:44:00",
                    "接生费").split(",");
            final var rec = sess.encode(rb.get(params));
            return (rec);
        }, "exec_unit,科室,audit_code,收入,bill_item,费用".split(","));

        println(result);
    }

    @Test
    public void bar2() {
        final var file = FileSystem.path("数字医院.xlsx", getClass());
        final var srchEngne = TableSearchEngine.of("第一用户", file, "费用,收入,科室,患者,医生".split(","));

        final var flds = "code,exec_unit,name,audit_code,charge_amount,effective_date,percentage_1_5,self_flag,separate_flag,suppress_flag,bill_item"
                .split(",");
        final var rb = IRecord.rb(Arrays.asList(flds));
        final var tpl = "$0,$1,$2,$3,$4,$5,1,1,1,1,$6";
        final Object[] params = FT(tpl, UUID.randomUUID(), "普通外科", "血常规化验费用", "化验收入", 100, "2020-10-13 00:44:00", "接生费")
                .split(",");
        final var encoder = srchEngne.getEncoder("exec_unit,科室,audit_code,收入,bill_item,费用".split(","));

        println(encoder.apply(rb.get(params)));
    }

    /**
     * IRecord 的path的演示
     */
    @Test
    public void quz() {
        final var tt = REC("a", REC("b", Arrays.asList(0, 1, REC("c", Arrays.asList("ABCDEFGH".split(""))), 3, 4)));
        println("quz","--->", tt.pathget("a/b/2/c/4", e -> e));
    }

    @Test
    public void quz2() {
        final BiFunction<String, Object, Object> parser = (k, e) -> e instanceof String ? Json.json2map(e) : e;
        final var srchEngne = new TableSearchEngine();
        final var config = REC("url","jdbc:mysql://localhost:3306/klcgraph?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=True");
        srchEngne.setConfig(config); // 数据库配置
        srchEngne.addAlgorithm(KEY_VALUE).addIndexEngine("t_vertex", (x, y) -> "id,name".split(",")); // 创建索引引擎
        final var encoder = srchEngne.getEncoder("name,t_vertex".split(","));
        final var decoder = srchEngne.getDecoder(e -> e.str("Attributes"), "name,t_vertex".split(","));
        
        for (int i = 0; i < 10; i++) {
            final var r1 = encoder.apply(REC("name", "中性粒细胞"));
            final var r2 = decoder.apply(REC("name", 1429));
            println(r2);
            println(r1);

            println(r2.pathget("name/en", parser, Object::toString));
            println(r2.pathget("name/tags", parser, (ArrayList<String> e) -> e));
        } // for

    }
    
    @Test
    public void quz3() {
        //绑定测试
        println(KTB("key1,table1,key2,table2"));
        println(KTB("key1,table1,key2,table2;key11,key12:table1;key21,key22:table2;"));
        
        final DateTimeFormatter DTF = CronTime.dtf("yyyy-MM-dd HH:mm:ss");
        final var srchEngne = new TableSearchEngine();
        final var config = REC("url",
                "jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=True");
        srchEngne.setConfig(config); // 数据库配置
        srchEngne.addAlgorithm(KEY_VALUE).addIndexEngine("t_vertex", (x, y) -> "id,name".split(",")); // 创建索引引擎
        final var encoder = srchEngne.getEncoder(KTB("v0,v1:t_vertex")); // 字段绑定,字段v0,v1的值即keyword都需要使用t_vertex的索引如:name或id索引进行检索

        final var names = "苹果,草莓,土豆,西瓜,牛肉,羊肉".split(","); // 产品列表
        final var rb = IRecord.rb("v0,v1,Attributes");
        final var ll = new LinkedList<IRecord>();
        final var dr_tpl = "借    $0         $1"; // 借方模板
        final var cr_tpl = "贷    银行存款   $1"; // 贷方模板
        final var dr_rb = LittleTree.IRecord.rb("amount,quantity,price,code,createtime");
        final var cr_rb = LittleTree.IRecord.rb("code,createtime");

        for (int i = 0; i < 10; i++) { // 交易清单
            final var code = UUID.randomUUID(); // 交易
            for (var name : names) { // 产品明细
                if (Math.random() > 0.5)
                    continue; // 随机生成订单
                final var amount = new Random().nextInt(1000);
                final var quantity = new Random().nextInt(100) + 1;
                final var price = amount / (quantity*1.0);
                final var createtime = LocalDateTime.now().format(DTF);
                final var dr_attrs = dr_rb.get(amount, quantity, price, code, createtime).json();
                final var cr_attrs = cr_rb.get(code, createtime).json();
                final var dr_entry = rb.get(FT(dr_tpl, name, dr_attrs).split("\\s{2,}")); // 由于日期类型含有空格坐这里使用{2,}
                final var cr_entry = rb.get(FT(cr_tpl, amount, cr_attrs).split("\\s{2,}"));
                Stream.of(dr_entry, cr_entry).forEach(e -> {
                    ll.add(e.derive("Relation", code));
                });
            } // for
        } // for

        final var dfm = ll.stream().map(encoder).collect(DFrame.dfmclc);
        println(dfm);

        final var dataApp = new DataApp() {
        }.reload2(LittleTree.IRecord.REC(config.toMap()));

        /**
         * 数据插入的演示
         */
        dataApp.withTransaction(sess -> {
            final var sqls = dfm.rowS().map(e -> LittleTree.IRecord.REC(e.toMap()))
                    .map(e -> SQL.of("t_edge", e).insert()).collect(Collectors.toList());
            for (var sql : sqls) {
                println(sess.sql2execute2int(sql), sql);
            }
        });
    }

}
